From comments in <https://github.com/cofacts/rumors-line-bot/pull/169|#169>: • `Query.context` is a little bit confusing with apollo context • `UserContext.state` & `UserContext.data` should be non-nullable
*<https://github.com/cofacts/rumors-line-bot/compare/a28f1b6b5ba2...8a390abf8dac|8 new commits> pushed to <https://github.com/cofacts/rumors-line-bot/tree/dev|`dev`>* <https://github.com/cofacts/rumors-line-bot/commit/080040ad2857b3c1d410465f4ccb5a755f48caf7|`080040ad`> - GraphQL authentication & context population <https://github.com/cofacts/rumors-line-bot/commit/30c8a3e52d0715a56eb6eace1484d834eb29cfe4|`30c8a3e5`> - Implement authentication, @auth directive and context field <https://github.com/cofacts/rumors-line-bot/commit/da8ccf6e33848f919e4459fbe91d3b7391052851|`da8ccf6e`> - Redundent jest.mock() as manual mocks for node modules will always load. <https://github.com/cofacts/rumors-line-bot/commit/f24191c880cf28a4fb879d64a1f440ea76071f14|`f24191c8`> - Add "manual" (auto) mock for redisClient so that all redisClient deps are mocked (such as in graphql/__tests__/insights) <https://github.com/cofacts/rumors-line-bot/commit/8dfa0c12afe6b0f6c8b49b798e4474c955450a89|`8dfa0c12`> - Prettier fix <https://github.com/cofacts/rumors-line-bot/commit/5295edb20990e761d51773539fab7903d37fc657|`5295edb2`> - Avoid calling the real redisClient in unit tests <https://github.com/cofacts/rumors-line-bot/commit/97b491de65d9a67c9c92bbdb4ac4118ff8f8359f|`97b491de`> - Add userId in GraphQL context after authentication <https://github.com/cofacts/rumors-line-bot/commit/8a390abf8dac39ad4701a9870628cbb1f06dad0c|`8a390abf`> - Merge pull request #169 from cofacts/auth-api
*<https://github.com/cofacts/rumors-line-bot/compare/8a390abf8dac...c5b684609691|9 new commits> pushed to <https://github.com/cofacts/rumors-line-bot/tree/dev|`dev`>* <https://github.com/cofacts/rumors-line-bot/commit/d36d76e47d90f391580d4ca5866aab14aa1efcf5|`d36d76e4`> - Implements mutation GraphQL endpoints for LIFF <https://github.com/cofacts/rumors-line-bot/commit/deb8bdd8075e5107db100ca2062caff5d5dccaba|`deb8bdd8`> - Remove submitReplyRequest because it is no longer needed <https://github.com/cofacts/rumors-line-bot/commit/ea856c552b8e8612936609b8fec6773c7a53d31d|`ea856c55`> - Remove submitArticle mutation because it's not needed <https://github.com/cofacts/rumors-line-bot/commit/b853bed252645822f9a81eccd79a9b72160efb64|`b853bed2`> - Prettier fix <https://github.com/cofacts/rumors-line-bot/commit/7860ec7dcc8c773ee25755d1563e26a3a4d16ac1|`7860ec7d`> - Add unit test for gql <https://github.com/cofacts/rumors-line-bot/commit/8ec314510a5e31c4de95248b3e6b09caa690a9b6|`8ec31451`> - Lint fix <https://github.com/cofacts/rumors-line-bot/commit/cc864507472181a1d2d713d18e5ecb675ac41824|`cc864507`> - gql error handling test. For test coverage... <https://github.com/cofacts/rumors-line-bot/commit/f86275a983ddd303333466dea15de103e17159ca|`f86275a9`> - Prettier fix <https://github.com/cofacts/rumors-line-bot/commit/c5b684609691bad8ec9ed6bd83df397dae310f40|`c5b68460`> - Merge pull request #170 from cofacts/mutation-api
Successfully deployed <https://github.com/cofacts/rumors-line-bot/commit/8a390abf8dac39ad4701a9870628cbb1f06dad0c|`8a390ab`> to <https://dashboard.heroku.com/apps/rumors-line-bot-staging/activity/builds/d14cc973-eef1-4425-9095-7c854349ac09|rumors-line-bot-staging>
*<https://github.com/cofacts/rumors-line-bot/compare/c5b684609691...8cc7ede5ddaf|8 new commits> pushed to <https://github.com/cofacts/rumors-line-bot/tree/dev|`dev`>* <https://github.com/cofacts/rumors-line-bot/commit/9d7f9b991f55c65a5f282ef0e11f1e0307099b1a|`9d7f9b99`> - Setup svelte liff and server build <https://github.com/cofacts/rumors-line-bot/commit/0bb6c769cdefba3d5d1589579d3fc3096c2779b7|`0bb6c769`> - audit fix <https://github.com/cofacts/rumors-line-bot/commit/51673df03e493ef42ddc49abbd3cfee1789d1396|`51673df0`> - Add liff proxy in dev mode <https://github.com/cofacts/rumors-line-bot/commit/eb8d1a7859035ff2b936544b29521d590465fbc6|`eb8d1a78`> - Add basic svelte setup <https://github.com/cofacts/rumors-line-bot/commit/0c2d09f027979d223b13077a61796da77fdc49ef|`0c2d09f0`> - Svelte i18n and corejs polyfill <https://github.com/cofacts/rumors-line-bot/commit/711fe7f2fb924332b0d94991777211c2fe3a1bfb|`711fe7f2`> - Imports polyfills that supports Safari10 and Android 52 <https://github.com/cofacts/rumors-line-bot/commit/10bb13afcf58cda3e5a09a68f61b13df3aeecd28|`10bb13af`> - Eslint ignore built liff/* <https://github.com/cofacts/rumors-line-bot/commit/8cc7ede5ddaf463e80977208ae97a93c81fa68f5|`8cc7ede5`> - Merge pull request #171 from cofacts/svelte-liff
This channel will get notifications from <https://github.com/cofacts|cofacts> for: `issues`, `pulls`, `public`
This channel will get notifications from <https://github.com/cofacts|cofacts> for: `issues`, `pulls`, `public`, `comments`, `reviews`
To see <https://github.com/cofacts/rumors-line-bot/issues/162|#162>
Stack Overflow
Javascript: best Singleton pattern
Possible Duplicate: Simplest/Cleanest way to implement singleton in JavaScript? I'm using this pattern for singletons, in the example the singleton is PlanetEarth: var NAMESPACE = function ()...
Stack Overflow
Simplest/Cleanest way to implement singleton in JavaScript?
What is the simplest/cleanest way to implement singleton pattern in JavaScript?
khalilstemmler.com
When to Use a Private Constructor | TypeScript OOP | Khalil Stemmler
In this blog post, I explain how using a private constructor helps to force a single way to create an object, and why it's most commonly used with the Factory Pattern.
Comment on #182 Feature/162 setup db
Update: as <https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP/2020-05|discussed in Slack> we decided to add a comment to constructor to indicate that the users of `CofactsMongoClient` should never call `new` by themselves. When we adopt Typescript in the future, we will make the constructor private to make sure that users of `CofactsMongoClient` can only retrieve its singleton instance via `getInstance()` static method. `CofactsMongoClient` is dedicated to connecting to Cofacts LINE bot mongodb, not something that is generalized. ES6 class is used so that it's easier to define method and update the client type in the same time, also ensures a smoother updater when we rewrite in Typescript.
docs.mongodb.com
cofacts.hacktabl.org
Cofacts - Connecting facts and instant messages
Cofacts is a collaborative system connecting instant messages and fact-check reports or different opinions together. It’s a grass-root effort fighting mis/disinformation in Taiwan.
Comment on #248 Fix/text expansion
Merge base temporarily changed to new page UI for correct diff. Will change back to dev benefits merge.
Comment on #247 Feature/new pages ui
Seems that in staging site, `user` being `null` would break `Avatar` and throw exception. I think the implementation of `<Avatar>` should guard against `null`.
Comment on #247 Feature/new pages ui
Mobile menu has the same z-index with result dropdown but comes later in DOM, thus it is coming through: <https://user-images.githubusercontent.com/108608/80872659-d78d9100-8ce5-11ea-87e3-61657e99221d.gif|z-index> May need to increase z-index here, or form a stacking context with `z-index: 0` for mobile menu to contain the badge?
Comment on #247 Feature/new pages ui
As discussed <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1587274861203800|in Slack>, please don't use `withData` in non-page components. Just use them on components under `pages/` directory.
Comment on #247 Feature/new pages ui
Seems that the padding is too large in mobile version, names and avatar do not align in center. <https://user-images.githubusercontent.com/108608/80833043-5ddf9f80-8c20-11ea-83e7-e8e3722f4d24.png|image> You can use object / array notation on `py` for setting this responsively <https://material-ui.com/system/basics/#object|https://material-ui.com/system/basics/#object>
Comment on #247 Feature/new pages ui
Inconsistent size of thumb-up/down button and the reason button in mobile view. <https://user-images.githubusercontent.com/108608/80891170-f5aebd80-8cf4-11ea-8163-818ee6de925a.png|image> Corresponding mockup: <https://user-images.githubusercontent.com/108608/80891197-1f67e480-8cf5-11ea-851f-39bc14f9c875.png|image>
Comment on #247 Feature/new pages ui
I think we can open another ticket for implementing the real "for you" count listed in spec: <https://g0v.hackmd.io/iJm9_nZaTA2GyInn7ycxoA|https://g0v.hackmd.io/iJm9_nZaTA2GyInn7ycxoA> The "自己沒有送過任何 normal articleReply" part has no API yet, while "article.replyRequestCount >= N (default N = 2)" and "沒有任何 normal articleReply 符合「正feedback>負feedback && status == "NORMAL"」" are currently available in `ListArticle` filter.
Comment on #247 Feature/new pages ui
Search result for replies is different from mockup. It should be listing replies that has the query text, rather than articles that has the query text. Mockup: <https://user-images.githubusercontent.com/108608/80891388-3a872400-8cf6-11ea-9ecc-dfd781fd27fc.png|image> Current: <https://user-images.githubusercontent.com/108608/80891392-4377f580-8cf6-11ea-99c0-fae928ed5f47.png|image> This may be huge so can include in future PRs.
Comment on #247 Feature/new pages ui
You also need `vote` under each feedbacks, because the you are using `vote` to move feedbacks in the right tab. Currently both tabs are empty because no feedback has `vote` field...... <https://user-images.githubusercontent.com/108608/80891094-61445b00-8cf4-11ea-82a2-eda5e2b83054.png|image>
g0v.hackmd.io
Comment on #247 Feature/new pages ui
<https://github.com/orgs/cofacts/projects/5#card-37456782|https://github.com/orgs/cofacts/projects/5#card-37456782> added here
Comment on #247 Feature/new pages ui
card added here: <https://github.com/orgs/cofacts/projects/5#card-34990256|https://github.com/orgs/cofacts/projects/5#card-34990256>
Comment on #182 Feature/162 setup db
You may reset `MockDate` here
Comment on #153 Update all dependencies
*PR has been edited* :construction_worker: This PR has received other commits, so Renovate will stop updating it to avoid conflicts or other problems. If you wish to abandon your changes and have Renovate start over you may click the "rebase" checkbox in the PR body/description.
Comment on #153 Update all dependencies
<https://coveralls.io/builds/30522585|Coverage Status> Coverage decreased (-5.1%) to 85.901% when pulling *<https://github.com/cofacts/rumors-api/commit/a64cc97a8f82f0c4bcd3b9f5946f4b55feb91ea9|a64cc97> on renovate/all* into *<https://github.com/cofacts/rumors-api/commit/4e8354b1aed320fc76cdeb09a4c1468822e09956|4e8354b> on master*.
Comment on #153 Update all dependencies
The Elasticsearch js library we are <https://www.npmjs.com/package/elasticsearch|currently using> is deprecated, thus we are migrating to the <https://www.elastic.co/blog/new-elasticsearch-javascript-client-released|new client>. 95% of the changes in this PR is to mitigate this <https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/6.x/breaking-changes.html|breaking change>: > The returned value of an API call will no longer be the body, statusCode, and headers for callbacks and just the body for promises. The new returned value will be a unique object containing the body, statusCode, headers, warnings, and meta, for both callback and promises. Therefore a majority of the code change is destructuring `body` from the all the values the elasticsearch client returns. We remove elasticsearch log related setup, since the new client does not have an integrated logger anymore. We add unit test to `auth.js`, in which some of its logic binding to passport cannot be tested, thus the coverage goes down a bit. Lastly, the version of submodule rumors-db is also updated. In latest changes, `.env` file is removed from rumors-db codebase, thus we need to provide ELASTICSEARCH_URL manually in package.json of rumors-api, otherwise it will break environments like Travis CI.
Comment on #247 Feature/new pages ui
其實我是指左邊兩顆 vote 按鈕,與右邊灰底的顯示部分不一樣高 <https://user-images.githubusercontent.com/108608/80921136-0ddf1500-8da7-11ea-9607-e723cb5b942d.png|image> Mockup 裡,雖然 mobile / desktop 下的 button 高度不同,但左右兩塊都是等高的。
Comment on #247 Feature/new pages ui
mobile 下, avatar 應該要跟右側文字置中。目前這樣好像有點太低了 <https://user-images.githubusercontent.com/108608/80921817-3ff27600-8dab-11ea-959e-14a0224b806d.png|image>
Comment on #247 Feature/new pages ui
Actually, replies page has different filter from article page. Mockup: <https://user-images.githubusercontent.com/108608/80923827-88646080-8db8-11ea-8dea-faf365456f67.png|image> Spec: <https://g0v.hackmd.io/ZZWHWi2BTuyhkSWzAvKLAw#%E9%81%8E%E6%BF%BE%E9%81%B8%E9%A0%85%EF%BC%9A|https://g0v.hackmd.io/ZZWHWi2BTuyhkSWzAvKLAw#%E9%81%8E%E6%BF%BE%E9%81%B8%E9%A0%85%EF%BC%9A> The API for "我查核過" and reply type filtering is still on the way, but "還未有有效查核", "熱門回報" and "熱門討論" are legit `ListArticle` filters already (`hasPositiveFeedbackArticleReply`, `replyRequestCount` and `replyCount` respectively). Considering the size of this change, I think we can handle this in future PRs, may need a ticket for this.
Comment on #247 Feature/new pages ui
card added here: <https://github.com/orgs/cofacts/projects/5#card-37494391|https://github.com/orgs/cofacts/projects/5#card-37494391>
Review on #247 Feature/new pages ui
LGTM! Let's ship it to staging <https://github.githubassets.com/images/icons/emoji/shipit.png|:shipit:>
Current implementation (puppeteer) eats up too much resource and the its throughput cannot keep up with the usage of rumors-api. We should consider other solutions as well. *Resources* Previous research: <https://github.com/cofacts/rumors-api/issues/41|cofacts/rumors-api#41> Web archiving tools by IIPC (behind wayback machine) <https://github.com/iipc/awesome-web-archiving|https://github.com/iipc/awesome-web-archiving> *Archiver* • Python + headless chrome <https://github.com/internetarchive/brozzler|https://github.com/internetarchive/brozzler> • Headless chrome <https://github.com/N0taN3rd/Squidwarc|https://github.com/N0taN3rd/Squidwarc> • Headless chrome with queue <https://github.com/yujiosaka/headless-chrome-crawler|https://github.com/yujiosaka/headless-chrome-crawler> • Save all in one html file <https://github.com/Y2Z/monolith|https://github.com/Y2Z/monolith> *Text summarization (w/ Chinese upport)* • request + newspaper3k (Python3) <https://newspaper.readthedocs.io/en/latest/|https://newspaper.readthedocs.io/en/latest/> *Misc* • Readability + readability-readarable <https://github.com/mozilla/readability#whats-readability-readerable|https://github.com/mozilla/readability#whats-readability-readerable>
src/graphql/models/Article.js:138-158
``` requestedForReply: { type: GraphQLBoolean, description: 'If the current user has requested for reply for this article', resolve: async ({ id }, args, { userId, appId, loaders }) => { assertUser({ userId, appId }); const userReplyRequests = await loaders.searchResultLoader.load({ index: 'replyrequests', body: { query: { bool: { must: [{ term: { userId } }, { term: { articleId: id } }], }, }, }, }); return userReplyRequests && userReplyRequests.length > 0; }, }, ```
Comment on #248 Fix/text expansion
We can use this so that the translators don't need to handle the triangles: ``` ({expanded ? t`Show Less` + ' ▲' : t`Show More` + ' ▼'}) ``` or ``` ({expanded ? `${t`Show Less`} ▲` : `${t`Show More`} ▼`}) ```
Comment on #248 Fix/text expansion
Not sure why, but there are some weird cases that need to trace code to figure out why <https://user-images.githubusercontent.com/108608/81078431-cf6d6580-8f20-11ea-9f84-6179c4ba4342.png|image> The article content is `555`. Can be found by searching `555` in page. Other similar scenario are: <https://user-images.githubusercontent.com/108608/81078509-ec099d80-8f20-11ea-8040-4ee1f7cccce0.png|image> <https://user-images.githubusercontent.com/108608/81078549-fd52aa00-8f20-11ea-94b4-6f2fef72861e.png|image>
Comment on #246 Update all dependencies
Blocked by <https://github.com/storybookjs/storybook/issues/10631|storybookjs/storybook#10631>
Comment on #248 Fix/text expansion
I suggest adding the component to storybook so that we can get visual documentation & snapshot testing
g0v.hackmd.io
Comment on #181 LIFF asking for reply feedback
Update: 1. abort LIFF on desktop <https://camo.githubusercontent.com/425d8a29fc7b947ffbbc9ca790a714c00c0ee8eb/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f32353230343736353734383931643233303762643131343533326165323237372e676966|https://camo.githubusercontent.com/425d8a29fc7b947ffbbc9ca790a714c00c0ee8eb/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f32353230343736353734383931643233303762643131343533326165323237372e676966> 2. explicitly tell user that we have recorded their feedback (regardless of them inputting the reason or not) in LIFF <https://camo.githubusercontent.com/59a3074d175f7d205d2e1eafaacb6c92f2a04171/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f62313061303365653566333061623433323163323437386161316634663735342e706e67|https://camo.githubusercontent.com/59a3074d175f7d205d2e1eafaacb6c92f2a04171/68747470733a2f2f73332d61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f6730762d6861636b6d642d696d616765732f75706c6f6164732f75706c6f61645f62313061303365653566333061623433323163323437386161316634663735342e706e67>
#184 Put reason response & share response in parallel
As discussed in <https://g0v.hackmd.io/@mrorz/BksBf58KI#%E9%80%81%E5%87%BA-source-%E8%88%87-reason-%E5%BE%8C%E7%9A%84%E8%A8%8A%E6%81%AF%E9%87%8D%E8%A4%87%E5%95%8F%E9%A1%8C|https://g0v.hackmd.io/@mrorz/BksBf58KI#%E9%80%81%E5%87%BA-source-%E8%88%87-reason-%E5%BE%8C%E7%9A%84%E8%A8%8A%E6%81%AF%E9%87%8D%E8%A4%87%E5%95%8F%E9%A1%8C> This PR turns the 2 bubbles after LIFF response into carousel to make it more compact, hopefully the message will not overwhelm the user. <https://user-images.githubusercontent.com/108608/81098815-790e2000-8f3c-11ea-8c1d-d2917421ab65.png|image> Note that • In response to source (first carousel), both bubble are all call-to-actions (we want user to both provide more info and share) • In response to reason (2nd carousel), not many people updates their own reason, thus use gray color instead; also, the update bubble is moved to the right (2nd bubble).
Comment on #184 Put reason response & share response in parallel
*Pull Request Test Coverage Report for <https://coveralls.io/builds/30576473|Build 771>* • *2* of *2* *(100.0%)* changed or added relevant lines in *2* files are covered. • No unchanged relevant lines lost coverage. • Overall coverage increased (+*0.02%*) to *98.652%* * * * * * * *:yellow_heart: - <https://coveralls.io|Coveralls>*
Comment on #248 Fix/text expansion
this seems like the old behavior of original commit, but I rebase the commit, it should look like these now: <https://user-images.githubusercontent.com/12843409/81135340-5276d600-8f8a-11ea-806c-b92fbfde2c68.png|截圖 2020-05-06 上午11 10 29> <https://user-images.githubusercontent.com/12843409/81135343-560a5d00-8f8a-11ea-873a-99dba391476d.png|截圖 2020-05-06 上午11 10 14>
Comment on #248 Fix/text expansion
It seems that it only happens on specific articles that has only 1 line, and the line is super short, on desktop. You can search for `555` on <https://cofacts.hacktabl.org/replies|staging> to see the following sample <https://user-images.githubusercontent.com/108608/81135607-72f36000-8f8b-11ea-975b-7a81433e250a.png|image>
Comment on #248 Fix/text expansion
Confirmed that its' fixed after rebase.
#249 Feature/new article details page ui
New article details page UI <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=681%3A0|mockup>
#250 New Pagination component UI
Change pagination to infinity load
Comment on #182 Feature/162 setup db
But `null` and `undefined` are different in mongodb. For example ``` db.collection('inventory').find({ item: null }); ``` ``` db.collection('inventory').find({ item: { $exists: false } }); ``` I'm not sure there is any effect in the future, so I choose the precise defines.
tico.chat
Tico | Where better conversation happens
The considerate messenger. Chat with whom you care about always at the best moments and times
meet.jit.si
Join a WebRTC video conference powered by the Jitsi Videobridge
CodePen
Mobile - Fixed footer unless keyboard is shown
...
Stack Overflow
How to make fixed-content go above iOS keyboard?
I can only find questions where people have the opposite problem. I want my fixed content to go above the iOS keyboard. Image of the problem: I want iOS to behave like Android. Is there a simpl...
HackMD
20200408 會議紀錄 ===== > Workis: MrOrz, bil, lucien > 線上:志超 > 線上開會:<https://tico.chat/powercall?room=>
#186 FeatureRequest: Share results to other chat rooms
Hi all, I really enjoy your works with cofacts chatbot. I can easily distinguish the truth of messages from my parents, that is reeeally good. However, there is a feature that I need is not in the current version. The feature I need is `sharing the results to other chat rooms`, such as my parent's private message or family channel etc. Thanks for your effort. You are the best.
material-ui.com
Tabs React component - Material-UI
Tabs make it easy to explore and switch between different views.
material-ui.com
Menu React component - Material-UI
Menus display a list of choices on temporary surfaces.
Comment on #182 Feature/162 setup db
Yeah I know about the `$exists`. But if you declare a field to be any type that is not null, say, a string, can you still assign `null` to that field?
Comment on #186 FeatureRequest: Share results to other chat rooms
Hi <https://github.com/shrimp509|@shrimp509> it's glad to see the chatbot helps :) If you feel like sharing the results from Cofacts to other chatrooms, you may either 1. long-press the reply and choose "share". After that you can select multiple messages to share (usually the reason and the references provided by the editor) and then choose the target chatrooms. 2. When the chatbot asks if the reply is useful, reply "yes". The chatbot will then encourage you to share this reply with friends. Option 2 works like this: <https://user-images.githubusercontent.com/108608/81205116-d23d8880-8ffc-11ea-9a15-fb2cd86e87b8.png|Screenshot_20200507-004353_2> <https://user-images.githubusercontent.com/108608/81205127-d5387900-8ffc-11ea-819c-a0b28bb97ef4.png|Screenshot_20200507-004411> We designed this flow because we really needs the user's feedback on usefulness of a reply, and we don't want to ask user to share a reply if they think it's not useful in the first place.
Comment on #186 FeatureRequest: Share results to other chat rooms
Got it!! I didn't notice the share button after choosing one of the results. Thanks for your detail explanation of why you design like this. I understand your consideration. Thank you again.
Comment on #172 New article creation flow
If `process.env.IMAGE_MESSAGE_ENABLED` is not true, image messages will not be tracked. Maybe we can extract this along with <https://github.com/cofacts/rumors-line-bot/blob/7a93a085e75e9d3ac1bcd8018b4a1625e4353bdf/src/webhook/index.js#L168|index.js L168>, <https://github.com/cofacts/rumors-line-bot/blob/7a93a085e75e9d3ac1bcd8018b4a1625e4353bdf/src/webhook/index.js#L179|index.js L179> to the beginning of <https://github.com/cofacts/rumors-line-bot/blob/7a93a085e75e9d3ac1bcd8018b4a1625e4353bdf/src/webhook/index.js#L83|process message>.
<@U038JQFE9> PR review 囉,請過目 <https://github.com/cofacts/rumors-line-bot/pull/182> mongoClient 的實作我覺得有些太複雜了,abstraction 也有點怪 QQ
MDN Web Docs
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.
Comment on #182 Feature/162 setup db
Yes, if using mongodb ``` $> db.ppl.insert({phoneNumber: null}) WriteResult({ "nInserted" : 1 }) $> db.ppl.insert({phoneNumber: '0912'}) WriteResult({ "nInserted" : 1 }) $> db.ppl.find() { "_id" : ObjectId("5eb3ad6a9a5e1f8e59885998"), "phoneNumber" : null } { "_id" : ObjectId("5eb3ad739a5e1f8e59885999"), "phoneNumber" : "0912" } ``` There are 2 options: 1. [require=true] Should be exist, then string or null 2. [require=false] It would be string or undefined (not exists) But I think yours is better to be less verbose first, and then update if need.
Comment on #182 Feature/162 setup db
btw, If we follow option 1, then we can query easily ``` db.collection('inventory').find({ itemA: null, itemB: 'book' }); ``` Not sure if it's important for now
Comment on #182 Feature/162 setup db
Hmm if I want to find a document that has one field that does not exist, the first idea that comes to my mind would be `{itemA: {$exists: false}}`, did not think of testing `null` in the first place. The syntax also mixes well with other conditions in place (i.e. `{itemA: {$exists: false}, itemB: 'book'}`). Slightly longer than the `null` version, but I think its occurrence in codebase should be less than field definitions.
Comment on #182 Feature/162 setup db
Seems that json schema we are currently using _does_ block non-required fields from being set to `null`. <https://user-images.githubusercontent.com/108608/81265339-824ed800-9075-11ea-8365-a52860f545f6.png|image>
Comment on #182 Feature/162 setup db
On the other hand, one draw back (?) of using non-required fields would be that it's a bit counterintuitive when we want to set a field conditionally, for instance, ``` const person = { name: 'foo', ...(revealGender ? {gender: input} : {}) } ``` Setting everything to required + allow null for some fields forces us to specify all fields, but is easier (?) to set conditional content: ``` const person = { name: 'foo', gender: revealGender ? input : null, bloodType: null, weight: null, height: null, birthday: null } ```
Comment on #182 Feature/162 setup db
> Seems that json schema we are currently using _does_ block non-required fields from being set to `null`. You are not using the current one ? Should be use `oneOf` in your demo case ?
Comment on #182 Feature/162 setup db
> Hmm if I want to find a document that has one field that does not exist, the first idea that comes to my mind would be `{itemA: {$exists: false}}`, did not think of testing `null` in the first place. I'm not sure that is the first idea. There are different usages in different situations. Let's talk about `newReplyNotifyToken` if it's expired or not working or something. I want to set to be `null`, not `undefined`, and find those documents by using `null` not `{$exists: false}`
Comment on #182 Feature/162 setup db
In the demo case I am testing if jsonschema can block `null` when it's assigned to non-required fields. Personally I think we should either stick to (a) field not-required + can't be null, or (b) all-field-required + can be null, not a mixture of (a) and (b). While the current code is in (b), in the demonstration I was trying to show that (a) also works as exptected.
Comment on #182 Feature/162 setup db
Interesting aspect of `newReplyNotifyToken`, didn't think of that. When `newReplyNotifyToken` is expired, I would ask the user if they want to delete the token. If they say yes, we invoke `db.collection('userArticleLinks').update({$unset: {newReplyNotifyToken: ''}})`. That's indeed longer than setting `newReplyNotifyToken` to `null`.
HackMD
【Cofacts 真的假的】Homepage for Developers - HackMD
【Cofacts 真的假的】Homepage for Developers ====== ## Source codes Cofacts is comprised of several com
HackMD
Updated at 2020/5/7
g0v.hackmd.io
g0v.hackmd.io
Comment on #182 Feature/162 setup db
*Pull Request Test Coverage Report for <https://coveralls.io/builds/30669027|Build 787>* • *59* of *62* *(95.16%)* changed or added relevant lines in *5* files are covered. • No unchanged relevant lines lost coverage. • Overall coverage decreased (*-0.5%*) to *96.177%* * * * * * * *:yellow_heart: - <https://coveralls.io|Coveralls>*
Comment on #250 New Pagination component UI
The vertical spacing is imbalanced <https://user-images.githubusercontent.com/108608/81465180-95d77b80-91fa-11ea-8dd5-63061579f71f.png|image> I suggest adding negative bottom margin to `ul.articleList` to undo the bottom margin of `ArticleItem`. Of course other solutions also apply (such as removing the bottom margin for last `ArticleItem` using `:last-child`), but we should still manage the margin of `ul.articleList`; it is still having the default margin defined by the browser. <https://user-images.githubusercontent.com/108608/81465177-87895f80-91fa-11ea-8af7-664d4a0d4b08.png|image>
Comment on #250 New Pagination component UI
Instead of using `refetch` that cleans up `listArticlesData`, please consider leveraging `fetchMore` which allows us to describe how new data is appended to `listArticlesData` using `updateQuery()`. In this way we don't need to maintain a separate state `articleEdges`. Reference: <https://www.apollographql.com/docs/react/data/pagination/|https://www.apollographql.com/docs/react/data/pagination/> Introductory post: <https://www.apollographql.com/blog/pagination-and-infinite-scrolling-in-apollo-client-59ff064aac61|https://www.apollographql.com/blog/pagination-and-infinite-scrolling-in-apollo-client-59ff064aac61> Also, we don't need to store `nextCursor` in separate state; we can just get the cursor from the last edge in the data. Lastly, the current implementation does not preserve the page if the user enters a detail page from the list and hit back to return. We hope that using `fetchMore` could solve the current issue, since apollo-cache should reserve the items loaded so far and next-router should manage the scroll position.
Comment on #250 New Pagination component UI
If we leverage `loadMore` and get cursor from last edge directly in `ArticlePageLayout`, we can leave the pagination logic entirely in where pagination happens, reduce the props passed to `LoadMore`. Personally I think `onClick` and `loading` should be enough; we can even detect if we reached the last page outside of `<LoadMore>`.
Review on #250 New Pagination component UI
It's a good try of changing the pagination into infinite load. I think we can • leverage `loadMore` instead of `refetch` and see if it helps with preserving pages when user navigates from detail page back to list page. • reduce the props passed to `LoadMore` as we encapsulate pagination logic in the component that uses `LoadMore`.
Review on #182 Feature/162 setup db
LGTM! Thanks for your patience and the explanation, very inspiring. It seems that it is possible to further simplify the logic of `MongoClient.getInstance()`, see the comment below.
Comment on #182 Feature/162 setup db
Seems that this is equivalent to: ``` // It returns promise anyway, no need for async in this function. // If we want to hint that this returns a promise, just use JSDoc `@returns {Promise<CofactsMongoClient>}` static getInstance() { // combines set-by-default and default setting return this._instance = this._instance || (async () => { const client = new CofactsMongoClient(MONGODB_URI); await client.mongoClient.connect(); return client; })(); } ``` Giving the async arrow function a good name can further improve its readability: ``` // Somewhere outside the class: // async function instantiateClientAndConnect() { const client = new CofactsMongoClient(MONGODB_URI); await client.mongoClient.connect(); return client; } // Then, back to inside the class, the code is super easy to understand now: // static getInstance() { return this._instance = this._instance || instantiateClientAndConnect(); } ```
#40 add empty list for missing articleCategories field
Fix this error: old version of articleCategories is null, instead of being initialized to empty list. ``` { "errors": [ { "message": "illegal_argument_exception", "locations": [ { "line": 2, "column": 3 } ], "path": [ "CreateArticleCategory" ], "extensions": { "code": "INTERNAL_SERVER_ERROR", "exception": { "name": "ResponseError", "meta": { "body": { "error": { "root_cause": [ { "type": "remote_transport_exception", "reason": "[VxKgRte][127.0.0.1:9300][indices:data/write/update[s]]" } ], "type": "illegal_argument_exception", "reason": "failed to execute script", "caused_by": { "type": "script_exception", "reason": "runtime error", "script_stack": [ "found = ctx._source.articleCategories.stream()\n .filter(", " ^---- HERE" ], "script": "\n def found = ctx._source.articleCategories.stream()\n .filter(ar -> ar.get('categoryId').equals(params.articleCategory.get('categoryId')))\n .findFirst();\n\n if (found.isPresent()) {\n HashMap ar = found.get();\n if (ar.get('status').equals('DELETED')) {\n ar.put('status', 'NORMAL');\n ar.put('userId', 'model_test');\n ar.put('appId', 'DEVELOPMENT_BACKEND');\n ar.put('updatedAt', '2020-05-07T11:56:48.759Z');\n } else {\n ctx.op = 'none';\n }\n } else {\n ctx._source.articleCategories.add(params.articleCategory);\n ctx._source.normalArticleCategoryCount = ctx._source.articleCategories.stream().filter(\n ar -> ar.get('status').equals('NORMAL')\n ).count();\n }\n ", "lang": "painless", "caused_by": { "type": "null_pointer_exception", "reason": null } } }, "status": 400 }, "statusCode": 400, "headers": { "content-type": "application/json; charset=UTF-8", "content-length": "1401" }, "warnings": null, "meta": { "context": null, "request": { "params": { "method": "POST", "path": "/articles/doc/zzyt710qo56u/_update", "body": "{\"script\":{\"source\":\"\\n def found = ctx._source.articleCategories.stream()\\n .filter(ar -> ar.get('categoryId').equals(params.articleCategory.get('categoryId')))\\n .findFirst();\\n\\n if (found.isPresent()) {\\n HashMap ar = found.get();\\n if (ar.get('status').equals('DELETED')) {\\n ar.put('status', 'NORMAL');\\n ar.put('userId', 'model_test');\\n ar.put('appId', 'DEVELOPMENT_BACKEND');\\n ar.put('updatedAt', '2020-05-07T11:56:48.759Z');\\n } else {\\n ctx.op = 'none';\\n }\\n } else {\\n ctx._source.articleCategories.add(params.articleCategory);\\n ctx._source.normalArticleCategoryCount = ctx._source.articleCategories.stream().filter(\\n ar -> ar.get('status').equals('NORMAL')\\n ).count();\\n }\\n \",\"lang\":\"painless\",\"params\":{\"articleCategory\":{\"userId\":\"model_test\",\"appId\":\"DEVELOPMENT_BACKEND\",\"aiModel\":\"bert\",\"aiConfidence\":1,\"positiveFeedbackCount\":0,\"negativeFeedbackCount\":0,\"categoryId\":\"mD2n7nEBrIRcahlYLAr7\",\"status\":\"NORMAL\",\"createdAt\":\"2020-05-07T11:56:48.759Z\",\"updatedAt\":\"2020-05-07T11:56:48.759Z\"}}},\"_source\":[\"articleCategories.*\"]}", "querystring": "", "headers": { "User-Agent": "elasticsearch-js/6.8.6 (linux 4.4.0-137-generic-x64; Node.js v12.14.1)", "Content-Type": "application/json", "Content-Length": "1269" }, "timeout": 30000 }, "options": { "warnings": null }, "id": 89085 }, "name": "elasticsearch-js", "connection": { "url": "<http://cofacts-db-staging:9200/>", "id": "<http://cofacts-db-staging:9200/>", "headers": {}, "deadCount": 0, "resurrectTimeout": 0, "_openRequests": 0, "status": "alive", "roles": { "master": true, "data": true, "ingest": true, "ml": false } }, "attempts": 0, "aborted": false } } } }, "authError": false } ], "data": { "CreateArticleCategory": null } } which can be reproduced by this mutation: ``` mutation { CreateArticleCategory( articleId: "zzyt710qo56u" categoryId: "mD2n7nEBrIRcahlYLAr7" aiModel: "bert" aiConfidence: 1.0 ) { articleId categoryId } }
Review on #40 add empty list for missing articleCategories field
LGTM! It works on staging, I think we can <https://github.githubassets.com/images/icons/emoji/shipit.png|:shipit:>
Comment on #249 Feature/new article details page ui
Please `npm run lint:fix` first. <https://travis-ci.org/github/cofacts/rumors-site/builds/684561774|https://travis-ci.org/github/cofacts/rumors-site/builds/684561774>
Comment on #249 Feature/new article details page ui
Suggest adding `copyBtnRef.current`, `content` and `onClick` to dependency array • Adding `copyBtnRef.current` is for the case when DOM of the the button is reconstructed, the `ClipboardJS` instance should be bound to the new DOM element instead. • Adding `content` and `onClick` is to prevent the case when these props are updated, ClipboardJS is still connecting to old callbacks that access an old JS closure.
Comment on #40 add empty list for missing articleCategories field
Deploying to production • Backup: `gcs/2020-05-10-before-migration` • Migrated at: TBD *1st round* ``` 16:59 ≎ ~/workspace/rumors-db ➠ npx babel-node db/migrations/202005-add-article-categories.js ResponseError: Response Error at IncomingMessage.<anonymous> (/Users/mrorz/workspace/rumors-db/node_modules/@elastic/elasticsearch/lib/Transport.js:296:25) at IncomingMessage.emit (events.js:205:15) at IncomingMessage.EventEmitter.emit (domain.js:471:20) at endReadableNT (_stream_readable.js:1137:12) at processTicksAndRejections (internal/process/task_queues.js:84:9) { name: 'ResponseError', meta: { body: { took: 4641, timed_out: false, total: 36068, updated: 3577, deleted: 0, batches: 4, version_conflicts: 423, noops: 0, retries: [Object], throttled_millis: 0, requests_per_second: -1, throttled_until_millis: 0, failures: [Array] }, statusCode: 409, headers: { 'content-type': 'application/json; charset=UTF-8', 'content-length': '133674' }, warnings: null, meta: { context: null, request: [Object], name: 'elasticsearch-js', connection: [Object], attempts: 1, aborted: false } } } ```
#41 Apply no-op and log results in migration 202005
This PR: • tells elasticsearch to do nothing when `articleCategories` exists • log everything when error occurs • log response when success
Comment on #40 add empty list for missing articleCategories field
Deploying to production • Backup: `gcs/2020-05-10-before-migration` • Migrated at: TBD *1st round* ``` 16:59 ≎ ~/workspace/rumors-db ➠ npx babel-node db/migrations/202005-add-article-categories.js ResponseError: Response Error at IncomingMessage.<anonymous> (/Users/mrorz/workspace/rumors-db/node_modules/@elastic/elasticsearch/lib/Transport.js:296:25) at IncomingMessage.emit (events.js:205:15) at IncomingMessage.EventEmitter.emit (domain.js:471:20) at endReadableNT (_stream_readable.js:1137:12) at processTicksAndRejections (internal/process/task_queues.js:84:9) { name: 'ResponseError', meta: { body: { took: 4641, timed_out: false, total: 36068, updated: 3577, deleted: 0, batches: 4, version_conflicts: 423, noops: 0, retries: [Object], throttled_millis: 0, requests_per_second: -1, throttled_until_millis: 0, failures: [Array] }, statusCode: 409, headers: { 'content-type': 'application/json; charset=UTF-8', 'content-length': '133674' }, warnings: null, meta: { context: null, request: [Object], name: 'elasticsearch-js', connection: [Object], attempts: 1, aborted: false } } } ``` *2nd round* ``` 18:20 ≎ ~/workspace/rumors-db ➠ npx babel-node db/migrations/202005-add-article-categories.js { body: { took: 3650, timed_out: false, total: 36068, updated: 0, deleted: 0, batches: 37, version_conflicts: 0, noops: 36068, retries: { bulk: 0, search: 0 }, throttled_millis: 0, requests_per_second: -1, throttled_until_millis: 0, failures: [] }, statusCode: 200, headers: { 'content-type': 'application/json; charset=UTF-8', 'content-length': '239' }, warnings: null, meta: { context: null, request: { params: [Object], options: [Object], id: 1 }, name: 'elasticsearch-js', connection: { url: '<http://localhost:62222/>', id: '<http://localhost:62222/>', headers: {}, deadCount: 0, resurrectTimeout: 0, _openRequests: 0, status: 'alive', roles: [Object] }, attempts: 0, aborted: false } } ```
g0v.hackmd.io
Comment on #129 List all article-replies
Replaced by `ListArticle`, no longer needs root-level article-reply list
#165 Implement `articleReplyFrom` filter in ListArticle
As discussed in <https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP/2020-05#ts-1588494165.332500|Slack>, we are adding this to `ListArticleFilter`: ``` articleReplyFrom: { userId: String, appId: String, exists: Boolean } ``` In order to filter out articles that • contains my reply (for "我查核過" filter in reply (actually replied _article_) list) • does not contain my reply (for <https://g0v.hackmd.io/iJm9_nZaTA2GyInn7ycxoA|navbar "for you" numbering>) • contains a certain user's reply • contains no certain user's reply Relates to • <https://github.com/cofacts/rumors-api/issues/60|#60> • <https://github.com/cofacts/rumors-api/issues/35|#35> • <https://github.com/cofacts/rumors-site/pull/247#discussion_r419149777|cofacts/rumors-site#247 (comment)>
#166 Implement Google analytics stats field in Article
Article should provide a field that returns analytics data for trend charts using <https://developers.google.com/analytics/devguides/reporting/core/v4|Google Analytics Reporting API> • Chatbot visit per day • Chatbot user count per day • Chatbot total visit in 30 days • Chatbot total user in 30 days • All above stats, but using Cofacts production site as target Related: • <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845>
#166 Implement Google analytics stats field in Article
Article should provide a field that returns analytics data for trend charts using <https://developers.google.com/analytics/devguides/reporting/core/v4|Google Analytics Reporting API> Related: • <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO?node-id=889:306#25950845>
Comment on #250 New Pagination component UI
I eventually remove the LoadMore component and leverage the whole component to `AarticlePageLayout`, because with only `onClick` & `loading` the LoadMore component seems similar to regular button, the actual logics are mostly move to `ArticlePageLayout`, it's a bit strange to have a Component call `LoadMore` while the actual load-more logics are written in upper component.
Comment on #250 New Pagination component UI
Sorry, I forgot to consider the case when there is no "next" button: <https://user-images.githubusercontent.com/108608/81596572-e4ea0000-93f6-11ea-9841-4d63cce39514.png|image> (It's fine in mobile, though; it's just that floating action buttons are covering the last item)
Review on #250 New Pagination component UI
Thanks for the modification! When clicking into detail pages & back out, the scroll position and previously loaded pages all worked like a charm. Spotted some minor styling issue, not a blocker though.
g0v.hackmd.io
g0v.hackmd.io
不知道為什麼 `GetArticle` 只要 query `requestedForReply` 就會變得很慢欸 0.0
Comment on #249 Feature/new article details page ui
Deployed to <https://cofacts.hacktabl.org/articles|https://cofacts.hacktabl.org/articles> so that everyone can inspect. <https://hub.docker.com/r/cofacts/rumors-site/tags|Docker image tags>: `pr249-en` and `pr249-tw`
g0v.hackmd.io
g0v.hackmd.io
tico.chat
Tico | Where better conversation happens
The considerate messenger. Chat with whom you care about always at the best moments and times
Figma
Created with Figma
cofacts.kktix.cc
2 個月一次,用一個下午與 Cofacts 一起工作闢謠解惑,讓不同意見突破同溫層。 來編輯小聚就送限量 Cofacts 貼紙。回應超過200篇,送委外設計LINE貼圖!感謝好想工作室 提供場地。
Comment on #182 Feature/162 setup db
Staging DB provisioned on Heroku, let's give it a shot <https://user-images.githubusercontent.com/108608/81890969-d740a000-95d9-11ea-91ac-8a389767eb25.png|螢幕快照 2020-05-14 上午11 52 59>
#251 Fix apollo-link-error causing SSR requests to halt
During SSR, an GraphQL Error can halt the processing of Apollo-link middlewares, causing the server-side render to return nothing. This PR 1. Always print the error to console 2. Fix SSR by detecting if `alert` exists in the global namespace (it's `undefined` during NodeJS SSR) From discussion: <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589437262448200?thread_ts=1588665581.350300&cid=C2PPMRQGP|https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589437262448200?thread_ts=1588665581.350300&cid=C2PPMRQGP> > 2. 我們用的 apollo-link-error 如果有 exception 的話,他就會無聲無息地悶不吭聲,讓後面的 apollo-client resolve 一整個卡住。我是在 BatchHttpLink 與 onError 中間插了一個印 console 的 link 才能抓到那個 error。 > 目前我們的 onError 裡頭用了 alert(),在 NodeJS 環境下並無此 function,所以他其實應該在 runtime 時遇到了 Reference error,但卻無聲無息。
#167 requestedForReply should return null when not logged in
Currently, `requestedForReply` of `Article` object type would throw error if the user is not logged-in. However, other fields that requires authentication (such as <https://github.com/cofacts/rumors-api/blob/master/src/graphql/models/ArticleReply.js#L68-L89|`ownVote`>, <https://github.com/cofacts/rumors-api/blob/master/src/graphql/models/ArticleReply.js#L42-L51|`canUpdateStatus`>) just returns `null` if the user is not logged in. `assertUser()` is meant for mutation resolvers and ordinary object type resolvers should avoid using `assertUser()`. Related discussion: • <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300|https://g0v-tw.slack.com/archives/C2PPMRQGP/p1588665581350300> • <https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP#ts-1588665581.350300|https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP#ts-1588665581.350300>
Comment on #167 requestedForReply should return null when not logged in
No idea why pr keeps failing no matter how many times I rebuild. `CreateReply` test cleanup always fails. On my local machine, I can reproduce the error for the first time I merge the code, but cannot reproduce at all after the first run. Soooo weird.
cofacts.kktix.cc
2 個月一次,用一個下午與 Cofacts 一起工作闢謠解惑,讓不同意見突破同溫層。 來編輯小聚就送限量 Cofacts 貼紙。回應超過200篇,送委外設計LINE貼圖!感謝好想工作室 提供場地。
Figma
Created with Figma
Comment on #249 Feature/new article details page ui
Currently if we click "Share" on desktop with a narrow browser screen, the share button does nothing. Let's combine `openMenu` and `handleShare`: • If `navigator.share` exists, use then invoke `navigator.share` • Otherwise, perform logic in `openMenu` We would only need one button this way
Comment on #249 Feature/new article details page ui
Looks like something worth joining <http://cofacts.hacktabl.org/storybook/index.html|http://cofacts.hacktabl.org/storybook/index.html> Otherwise we may forget about this component :P
Comment on #249 Feature/new article details page ui
`px` incorrect; you may also need to adjust `py` taking its content into consideration *as-is* <https://user-images.githubusercontent.com/108608/81927501-50f67f00-9616-11ea-9497-a4f8c51f00c1.png|image> *to-be* Spec: <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306> <https://user-images.githubusercontent.com/108608/81927523-5eac0480-9616-11ea-9321-bd2d0385e6eb.png|image>
Comment on #249 Feature/new article details page ui
This default assignment breaks `if (!article) {` early-return condition in L172 below. Therefore, if user mistyped the article ID, they are greeted with internal server error: <https://user-images.githubusercontent.com/108608/81925904-b8f79600-9613-11ea-80d7-c51ce8ebaa9f.png|image> I suggest 1. Move all hooks invocation forward to enable early-return 2. Use early return to guard unexpected condition 3. Push all destructuring assignments as late as possible, or at least after the early return blocks
Review on #249 Feature/new article details page ui
I did not went through all the files, here are the first batch of the comments. Some of them are regarding functionalities, which we can discuss. For comments on paddings / margins / borders, we can leave that to the future PRs (when mobile design is implemented)
Comment on #249 Feature/new article details page ui
Please re-adjust the padding so that it matches <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306|mockup>. • padding between content and separator should be 16px • last item should not have bottom separator
Comment on #249 Feature/new article details page ui
1. Seems that this line does not appear? Currently there is no separation between replies, which is a bit hard to read. <https://user-images.githubusercontent.com/108608/82017417-b0f03280-96b5-11ea-9b82-f19ee8656924.png|image> 2. According to <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=681%3A0|mockup> the horizontal line between replies should be solid lines.
Comment on #249 Feature/new article details page ui
Let's follow the mockup and limit the number of line of such message to 5 and mind its line breaks. <https://cofacts.hacktabl.org/article/16aoyuv6t0cwz|https://cofacts.hacktabl.org/article/16aoyuv6t0cwz> <https://user-images.githubusercontent.com/108608/81927029-8babe780-9615-11ea-98d8-f21a5d295fc8.png|image> Mockup: <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306>
Comment on #249 Feature/new article details page ui
Copy 請改成 > Inserting blank lines between reference items can improve readability in LINE. cc/ <https://github.com/LucienLee|@LucienLee>
Comment on #249 Feature/new article details page ui
margin top too big for this and the following cards *as-is* <https://user-images.githubusercontent.com/108608/81927953-1214f900-9617-11ea-8b44-02ec0ada917a.png|image> *to-be* <https://user-images.githubusercontent.com/108608/81928000-25c05f80-9617-11ea-8c51-0d10ef61904f.png|image>
Comment on #249 Feature/new article details page ui
This class does not seem to have any effect
Comment on #249 Feature/new article details page ui
The line on the top of Reference should be `dashed` not `dotted`
Comment on #249 Feature/new article details page ui
"I second that" button toggles the form that submits `replyRequest`, thus I think the state `requestedForReply` should link to that button. ( <https://github.com/LucienLee|@LucienLee> , do we have different state for "I second that" button if the user has requested reply? ) I don't see "I also wanna know" button in mockup now
Comment on #249 Feature/new article details page ui
As <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589357030428400?thread_ts=1589355054.427400&cid=C2PPMRQGP|discussed in slack> the new form should be collapsed (hidden) by default. <https://user-images.githubusercontent.com/108608/82015571-a16eea80-96b1-11ea-9bcb-626c1c4e43fa.png|image> Also there are <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589440429449700?thread_ts=1589355054.427400&cid=C2PPMRQGP|discussions> around having new URL for the state that has form expanded. I am OK with both URL or no URL solution.
#165 Implement `articleReplyFrom` filter in ListArticle
As discussed in <https://g0v-slack-archive.g0v.ronny.tw/index/channel/C2PPMRQGP/2020-05#ts-1588494165.332500|Slack>, we are adding this to `ListArticleFilter`: ``` articleReplyFrom: { userId: String, appId: String, exists: Boolean } ``` In order to filter out articles that • contains my reply (for "我查核過" filter in reply (actually replied _article_) list) • does not contain my reply (for <https://g0v.hackmd.io/iJm9_nZaTA2GyInn7ycxoA|navbar "for you" numbering>) • contains a certain user's reply • contains no certain user's reply Relates to • <https://github.com/cofacts/rumors-api/issues/60|#60> • <https://github.com/cofacts/rumors-api/issues/35|#35> • <https://github.com/cofacts/rumors-site/pull/247#discussion_r419149777|cofacts/rumors-site#247 (comment)>
fix some bugs and add some missing features mentioned <https://g0v.hackmd.io/8qj-pd_XTN-nOYMi-5ZBnw|here>
Current implementation (puppeteer) eats up too much resource and the its throughput cannot keep up with the usage of rumors-api. We should consider other solutions as well. *Resources* Previous research: <https://github.com/cofacts/rumors-api/issues/41|cofacts/rumors-api#41> Web archiving tools by IIPC (behind wayback machine) <https://github.com/iipc/awesome-web-archiving|https://github.com/iipc/awesome-web-archiving> *Archiver* • Python + headless chrome <https://github.com/internetarchive/brozzler|https://github.com/internetarchive/brozzler> • Headless chrome <https://github.com/N0taN3rd/Squidwarc|https://github.com/N0taN3rd/Squidwarc> • Headless chrome with queue <https://github.com/yujiosaka/headless-chrome-crawler|https://github.com/yujiosaka/headless-chrome-crawler> • Save all in one html file <https://github.com/Y2Z/monolith|https://github.com/Y2Z/monolith> *Text summarization (w/ Chinese upport)* • request + newspaper3k (Python3) <https://newspaper.readthedocs.io/en/latest/|https://newspaper.readthedocs.io/en/latest/> *Misc* • Readability + readability-readarable <https://github.com/mozilla/readability#whats-readability-readerable|https://github.com/mozilla/readability#whats-readability-readerable>
cofacts.kktix.cc
2 個月一次,用一個下午與 Cofacts 一起工作闢謠解惑,讓不同意見突破同溫層。 來編輯小聚就送限量 Cofacts 貼紙。回應超過200篇,送委外設計LINE貼圖!感謝好想工作室 提供場地。
Comment on #252 Fix/missing features
Seems that Material-UI's `TextField` applies a `flex-direction: column` to the root component of `TextField`, causing the control height not following the height of its container. Overriding the default `flex-direction` may allow `TextField` height in-sync with its container: <https://user-images.githubusercontent.com/108608/82112973-bf594f80-9784-11ea-8b97-6e3c4e397338.png|image>
Comment on #252 Fix/missing features
1. `overflow: scroll` will cause non-Mac browsers always display a scrollbar like this: <https://user-images.githubusercontent.com/108608/82112770-dac35b00-9782-11ea-8d7c-a8bff5ecf171.png|image> 2. In this case we should never need a scrollbar, thus I don't think we ever need `overflow` property. I suggest we remove `alignItems="center"` together, using the default value of `align-items`, which is `stretch` and should make flex items stretch to have equal height. Next thing is removing excessive wrapping `div`s surrounding the flex items, so that the dropdown components can be the direct child (flex item) of the flexbox. Under the power of `align-item: stretch`, they should then have the same height, achieving the style we want.
Comment on #252 Fix/missing features
Sometimes we would use `{start: undefined, end: <some-time>}` to find messages from the beginning of the project to a specific date. Therefore, I think we should also support the case with only `end` as well. ``` if (start) { filterObj[timeRangeKey] = {...filterObj[timeRangeKey], GTE: start}; } if (end) { filterObj[timeRangeKey] = {...filterObj[timeRangeKey], LTE: end}; } ```
Review on #252 Fix/missing features
Thank you for the timely fix! It's so glad to see the outdated `status` being replaced by the brand new `filter` mechanism :rocket: Please find below my suggestions regarding styles and filters applied. Also, regarding reply list (`pages/replies.js`), I am confirming with <https://github.com/LucienLee|@LucienLee> to see if we should apply a always-on filter on `replyCount` in this <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589365504440400|slack thread>. Let's follow up the discussion in slack.
Comment on #252 Fix/missing features
Articles with reply (`replyCount` > 0) but has no positive feedbacks should also be included, so we can drop `replyCount = 0` constraint
Comment on #252 Fix/missing features
Articles with reply `(replyCount > 0)` but has no positive feedbacks should also be included, so we can drop `replyCount = 0` constraint. Ref: <https://g0v.hackmd.io/@NFi0czulSemxCM8RNSlz8Q/HJ8xT3QVU/%2FahtI6xsFRQyxktrIlc1VcQ|spec>
Comment on #252 Fix/missing features
Need to check why `classes` is undefined in mobile <https://user-images.githubusercontent.com/108608/82113048-5cb48380-9785-11ea-8b7a-aca8653ebfdc.gif|filter-error>
Comment on #249 Feature/new article details page ui
Actually this collides with reply's localstorage cache. This is a bug that can be perceived in current production as well. Changing `text` to some other key should fix the bug; we can also open a separate issue, since this is not in the scope of this PR actually. <https://user-images.githubusercontent.com/108608/82118015-e88ad780-97a6-11ea-8541-057b3cb7ed06.png|螢幕快照 2020-05-16 下午6 53 59>
Comment on #249 Feature/new article details page ui
This `flex` is not needed. Instead, I think we can add `-webkit-line-clamp` (and other properties to make it work) <https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-line-clamp|https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-line-clamp> so that it displays `...` when text is truncated.
Comment on #249 Feature/new article details page ui
When there is no image on the right, we don't need `marginRight`. Therefore I suggest we should set `margin-left` on image instead.
Comment on #249 Feature/new article details page ui
font-size should be 14 according to <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=889%3A306|mockup>. Currently it's slightly larger than 14px due to Google chrome's user agent stylesheet <https://user-images.githubusercontent.com/108608/82119147-bd0beb00-97ae-11ea-955e-a002fa2b86c8.png|image>
Comment on #252 Fix/missing features
<https://user-images.githubusercontent.com/12843409/82119267-913d3500-97af-11ea-917e-db1faae0bc0d.png|截圖 2020-05-16 下午7 56 13> the `overflow: hidden` is because that when selecting custom time range, the total length would be too long that breaks the layout
Comment on #249 Feature/new article details page ui
I think that instead of customizing a button from browser style into primary button, we should use <https://material-ui.com/components/buttons/#contained-buttons|Material UI Contained Buttons with `disableElevation`>. It has better handle over hover & active states as well. The same goes to the button and the <https://material-ui.com/components/button-group/#disabled-elevation|buttonGroup> in `CreateReplyRequestForm`.
Comment on #252 Fix/missing features
Hmm I didn't think of that. I think we can have a wrapping flexbox here, allowing the sort control go to second line.
Review on #252 Fix/missing features
It is in a good shape now, I think are just a few steps away before pushing to production. • fix conflict • handling the case when date selector & sort dropdown break the screen • maybe showing only articles with replies in `/pages/replies` (discussion: <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589365504440400|https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589365504440400> )
Figma
Created with Figma
Figma
Created with Figma
material-ui.com
React Drawer 抽屉组件 - Material-UI
导航抽屉提供了一个访问您应用中的目标地址的途径。侧边栏被固定在屏幕的左侧或右侧,而它包含了一些补充内容。
Comment on #252 Fix/missing features
LGTM! Let's leave the <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1589365504440400|reply list discussion> for future PRs to keep the scope small. Thanks for your patience!
Comment on #249 Feature/new article details page ui
I found a weird case that my feedback is visible in API but not in UI. <https://user-images.githubusercontent.com/108608/82125422-6fa47380-97d8-11ea-8f9c-c034e02abcd6.png|螢幕快照 2020-05-17 上午12 48 24>
g0v.hackmd.io
#187 Translate all strings into Traditional Chinese
This is on the roadmap of deploying current staging chatbot to production. <https://user-images.githubusercontent.com/108608/82138971-36f7af00-9857-11ea-8e41-b6e14856cde1.png|image> <https://user-images.githubusercontent.com/108608/82138973-3ced9000-9857-11ea-87f2-61146b5216b6.png|image> <https://user-images.githubusercontent.com/108608/82138986-57276e00-9857-11ea-8019-d30d0626552c.png|image> <https://user-images.githubusercontent.com/108608/82138977-41b24400-9857-11ea-8739-ad32644c0562.png|image>
Comment on #187 Translate all strings into Traditional Chinese
*Pull Request Test Coverage Report for <https://coveralls.io/builds/30840342|Build 823>* • *0* of *0* changed or added relevant lines in *0* files are covered. • No unchanged relevant lines lost coverage. • Overall coverage remained the same at *98.438%* * * * * * * *:yellow_heart: - <https://coveralls.io|Coveralls>*
#253 Traditional Chinese translation for list pages
Translate to zh_TW of list pages, before pushing to production. Translations referring to the <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=0%3A1|mockup>. <https://user-images.githubusercontent.com/108608/82153073-dfc5fe80-9897-11ea-957b-b8def2b0a26e.png|image> <https://user-images.githubusercontent.com/108608/82153111-13088d80-9898-11ea-8059-a1b3970e2fb3.png|image> <https://user-images.githubusercontent.com/108608/82153118-1f8ce600-9898-11ea-9099-147f708a590e.png|image> <https://user-images.githubusercontent.com/108608/82153177-86aa9a80-9898-11ea-8976-f1b4c2a1e11e.png|image> <https://user-images.githubusercontent.com/108608/82153181-8d391200-9898-11ea-8312-286fab636dbe.png|image>
Comment on #253 Traditional Chinese translation for list pages
These are temporary components that is going to be replaced, so I don't translate these.
Comment on #237 Setup displayName of important component
A Google Tag Manager custom variable setup like below will be able to track the React component name (if it's static `displayName` is set) of the clicked element (or clicked element's ancestor): ``` function() { var currentNode = {{Click Element}}; var reactInstanceKey = Object.keys(currentNode).find(function(key){ return key.startsWith('__reactInternalInstance$'); }); if(!reactInstanceKey) return; var currentInst = currentNode[reactInstanceKey]; while(currentInst) { if(currentInst.elementType && currentInst.elementType.displayName && // Ignore names like "WithStyles(ForwardRef(ButtonGroup))" currentInst.elementType.displayName.indexOf('(') === -1) { return currentInst.elementType.displayName; } currentInst = currentInst.return; } } ``` However, most components in Cofacts code base do not have `displayName` -- some buttons we want to track isn't even an isolated component. I am switching to `data-ga` method property instead of `displayName`.
#254 Introduce data-ga and displayName tracking
*Google Tag Manager setup* *User defined variable `Clicked Element Path`* ``` function() { var currentNode = {{Click Element}}; var reactInstanceKey = Object.keys(currentNode).find(function(key){ return key.startsWith('__reactInternalInstance$'); }); if(!reactInstanceKey) return; var currentInst = currentNode[reactInstanceKey]; var path = []; while(currentInst) { if(currentInst.memoizedProps && currentInst.memoizedProps['data-ga']) { path.unshift(currentInst.memoizedProps['data-ga']); } else if(currentInst.elementType && currentInst.elementType.displayName && // Ignore names like "WithStyles(ForwardRef(ButtonGroup))" currentInst.elementType.displayName.indexOf('(') === -1) { path.unshift(currentInst.elementType.displayName); } currentInst = currentInst.return; } return path.join(' > '); } ```
g0v.hackmd.io
Comment on #253 Traditional Chinese translation for list pages
等你來答//交給你了//請你查證
#254 Introduce data-ga and displayName in Google Analytics tracking
This PR sends the `data-ga` property or `displayName` of the clicked component to Google Analytics, so that we can track click of component of interest. See the `eventCategory` (in non-bold text) on the right side of the screen recording: <https://user-images.githubusercontent.com/108608/82204954-5dd9e200-9938-11ea-95d4-f65308839c15.gif|onclick-path>. The innerText of the clicked element is sent as `eventLabel`. Collected events in Google analytics: <https://user-images.githubusercontent.com/108608/82203326-beb3eb00-9935-11ea-8b6b-f0bb9b6c4847.png|image> This fixes <https://github.com/cofacts/rumors-site/issues/237|#237> . *Related Spec* This PR implements "成效追蹤" part of the following spec: • <https://g0v.hackmd.io/ahtI6xsFRQyxktrIlc1VcQ#%E6%88%90%E6%95%88%E8%BF%BD%E8%B9%A4|Dubious messages> • <https://g0v.hackmd.io/ZZWHWi2BTuyhkSWzAvKLAw#%E6%88%90%E6%95%88%E8%BF%BD%E8%B9%A4|Latest replies> • <https://g0v.hackmd.io/@NFi0czulSemxCM8RNSlz8Q/HJ8xT3QVU/%2FN8I2-zkJTaS35BP8VH8ZQA|Hoax for you> (subset of Latest replies) *Google Tag Manager setup* <https://user-images.githubusercontent.com/108608/82202606-bd35f300-9934-11ea-9556-ceaee3ab223a.png|image> *User defined variable `Clicked Element Path`* This shows the the clicked item's component name (`<ComponentName>`) or `data-ga` property (`[ga propety]`) when their descendent is clicked. ``` function() { var currentNode = {{Click Element}}; if(!currentNode) return ''; var reactInstanceKey = Object.keys(currentNode).find(function(key){ return key.startsWith('__reactInternalInstance$'); }); if(!reactInstanceKey) return ''; var currentInst = currentNode[reactInstanceKey]; var path = []; while(currentInst) { if(currentInst.memoizedProps && currentInst.memoizedProps['data-ga'] && // data-ga may be passed down to multiple levels of child components. // we don't want to record duplicated 'data-ga'. path[0] !== '[' + currentInst.memoizedProps['data-ga'] + ']') { path.unshift('[' + currentInst.memoizedProps['data-ga'] + ']'); } else if(currentInst.elementType && currentInst.elementType.displayName && // Ignore names like "WithStyles(ForwardRef(ButtonGroup))" currentInst.elementType.displayName.indexOf('(') === -1) { path.unshift('<' + currentInst.elementType.displayName + '>'); } currentInst = currentInst.return; } return path.join(' ▸ '); } ``` *Trigger `Clicked element with path`* <https://user-images.githubusercontent.com/108608/82203039-5238ec00-9935-11ea-9d32-dbc87e68dbb2.png|image> *Tag `Click event to GA`* <https://user-images.githubusercontent.com/108608/82203158-814f5d80-9935-11ea-8eed-90328a0c2b71.png|image>
Comment on #237 Setup displayName of important component
We use both `data-ga` and `displayName` in the end. `data-ga` provides greater flexibility because we can set different names for different occurrences, while `displayName` makes sure all clicks under a component will be recorded no matter where it is rendered.
g0v.hackmd.io
#188 BadRequestError: request aborted
View details in Rollbar: <https://rollbar.com/mrorz/rumors-line-bot/items/208/|https://rollbar.com/mrorz/rumors-line-bot/items/208/> ``` BadRequestError: request aborted File "/app/node_modules/raw-body/index.js", line 231, in IncomingMessage.onAborted done(createError(400, 'request aborted', { File "events.js", line 310, in IncomingMessage.emit File "_http_server.js", line 532, in abortIncoming File "_http_server.js", line 525, in socketOnClose File "events.js", line 322, in Socket.emit File "net.js", line 672, in TCP.<anonymous> ```
Comment on #188 BadRequestError: request aborted
Should if this is due to normal usage (e.g. pressed an outdated button). If it is, we should configure rollbar to ignore such error.
Welcome to <https://togithub.com/renovatebot/renovate|Renovate>! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin. :vertical_traffic_light: To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged. * * * *Detected Package Files* • `package.json` (npm) *Configuration Summary* Based on the default config's presets, Renovate will: • Start dependency updates only once this onboarding PR is merged • Separate major versions of dependencies into individual branches/PRs • Do not separate patch and minor upgrades into separate PRs for the same dependency • Upgrade to unstable versions only if the existing version is unstable • Raise PRs immediately (after branch is created) • If semantic commits detected, use semantic commit type `fix` for dependencies and `chore` for all others • Keep existing branches updated even when not scheduled • Disable automerging feature - wait for humans to merge all PRs • Ignore `node_modules`, `bower_components`, `vendor` and various test/tests directories • Autodetect whether to pin dependencies or maintain ranges • Rate limit PR creation to a maximum of two per hour • Limit to maximum 20 open PRs at any time • Group known monorepo packages together • Use curated list of recommended non-monorepo package groupings :abcd: Would you like to change the way Renovate is upgrading your dependencies? Simply edit the `renovate.json` in this branch with your custom config and the list of Pull Requests in the "What to Expect" section below will be updated the next time Renovate runs. * * * You have configured Renovate to use branch `master` as base branch. *What to Expect* With your current configuration, Renovate will create 6 Pull Requests: Pin dependencies • Schedule: ["at any time"] • Branch name: `renovate/pin-dependencies` • Merge into: `master` • Pin <https://togithub.com/testing-library/jest-dom|@testing-library/jest-dom> to `4.2.4` • Pin <https://togithub.com/testing-library/react-testing-library|@testing-library/react> to `9.5.0` • Pin <https://togithub.com/testing-library/user-event|@testing-library/user-event> to `7.2.1` • Pin <https://togithub.com/DefinitelyTyped/DefinitelyTyped|@types/jest> to `24.9.1` • Pin <https://togithub.com/DefinitelyTyped/DefinitelyTyped|@types/node> to `12.12.39` • Pin <https://togithub.com/DefinitelyTyped/DefinitelyTyped|@types/react> to `16.9.35` • Pin <https://togithub.com/DefinitelyTyped/DefinitelyTyped|@types/react-dom> to `16.9.8` • Pin <https://togithub.com/facebook/react|react> to `16.13.1` • Pin <https://togithub.com/facebook/react|react-dom> to `16.13.1` • Pin <https://togithub.com/Microsoft/TypeScript|typescript> to `3.7.5` Update dependency typescript to v3.9.2 • Schedule: ["at any time"] • Branch name: `renovate/typescript-3.x` • Merge into: `master` • Upgrade <https://togithub.com/Microsoft/TypeScript|typescript> to `3.9.2` Update dependency @testing-library/jest-dom to v5 • Schedule: ["at any time"] • Branch name: `renovate/testing-library-jest-dom-5.x` • Merge into: `master` • Upgrade <https://togithub.com/testing-library/jest-dom|@testing-library/jest-dom> to `5.7.0` Update dependency @testing-library/react to v10 • Schedule: ["at any time"] • Branch name: `renovate/testing-library-react-10.x` • Merge into: `master` • Upgrade <https://togithub.com/testing-library/react-testing-library|@testing-library/react> to `10.0.4` Update dependency @testing-library/user-event to v10 • Schedule: ["at any time"] • Branch name: `renovate/testing-library-user-event-10.x` • Merge into: `master` • Upgrade <https://togithub.com/testing-library/user-event|@testing-library/user-event> to `10.3.1` Update dependency @types/jest to v25 • Schedule: ["at any time"] • Branch name: `renovate/jest-25.x` • Merge into: `master` • Upgrade <https://togithub.com/DefinitelyTyped/DefinitelyTyped|@types/jest> to `25.2.3` :children_crossing: Branch creation will be limited to maximum 2 per hour, so it doesn't swamp any CI resources or spam the project. See docs for `prhourlylimit` for details. * * * :question: Got questions? Check out Renovate's <https://docs.renovatebot.com/|Docs>, particularly the Getting Started section. If you need any further assistance then you can also <https://togithub.com/renovatebot/config-help/issues|request help here>. * * * This PR has been generated by <https://renovate.whitesourcesoftware.com|WhiteSource Renovate>. View repository job log <https://app.renovatebot.com/dashboard#cofacts/community-builder|here>.
g0v.hackmd.io
LINE TODAY
新增/ iOS版LINE 提供用Safari開啟連結的實驗功能 | Mobile01 | LINE TODAY
我們常會在LINE裡點開連結網址,然後LINE會用內部瀏覽器打開這個連結,不過若想再分享到LINE之外的地方(如FB、IG、訊息…等),就得再換成用Safari開啟,多了一道步驟,有點麻煩。 現在iOS版的LINE Labs裡,新增「一律用Safari開啟」的選項,讓你在LINE裡點擊連結時,會直接用Safari開啟網頁,包括LINE購物的頁面也是。 這樣一來就可以使用Safari的延伸工具,做外部分享或更多應用了,比方Safari有擋廣告的外掛,這樣點開看新聞連結,就不用受彈出廣告干擾了[愛心]。 其他如分享到備忘錄、翻譯、列印、做備註、加入書籤或稍後閱讀…等,也會因為直接用Safari瀏覽
#2 Replace WTFPL License by any other open license (Apache 2.0, ISC, MIT)
It would be really great to replace WTFPL license from published npm artifacts
Comment on #1 Configure Renovate
*Renovate is disabled* Renovate is disabled due to lack of config. If you wish to reenable it, you can either (a) commit a config file to your base branch, or (b) rename this closed PR to trigger a replacement onboarding PR.
Mozilla, CC 跟 Coil 成立的一個新的獎助金,贊助「Web Monetization」標準相關的開發與設計專案,申請時間到 6/12 <https://www.grantfortheweb.org/apply>
DEV Community
A guide to getting started with web monetization
Currently, iOS will show this when opening LIFF <https://user-images.githubusercontent.com/108608/82446442-3cfcc280-9ad9-11ea-9b97-a217cdcddca6.png|image> Related discussion: <https://g0v-tw.slack.com/archives/C2PPMRQGP/p1583323511054400|https://g0v-tw.slack.com/archives/C2PPMRQGP/p1583323511054400> This PR avoids this condition by moving `isInClient` API call to after `liff.init()`.
Comment on #189 Defer isInClient() call
*Pull Request Test Coverage Report for <https://coveralls.io/builds/30916892|Build 828>* • *0* of *0* changed or added relevant lines in *0* files are covered. • No unchanged relevant lines lost coverage. • Overall coverage remained the same at *98.438%* * * * * * * *:yellow_heart: - <https://coveralls.io|Coveralls>*
#190 LIFF trap source should guide user to other fact checkers
Response is now incorrect. According to <https://github.com/cofacts/rumors-line-bot/blob/dev/src/webhook/handlers/askingArticleSubmissionConsent.js#L35-L41|source code>, it should block article submission and shows hint to other fact checkers (see <https://github.com/cofacts/rumors-line-bot/blob/dev/src/webhook/handlers/__tests__/askingArticleSubmissionConsent.test.js#L57-L84|unit test>) Instead, it shows: <https://user-images.githubusercontent.com/108608/82446786-e2179b00-9ad9-11ea-8986-4c361d0c86e1.png|Screenshot_20200520-203235>
Comment on #188 BadRequestError: request aborted
Or maybe the user aborted the loading LIFF due to long waiting time?
Comment on #160 Add add-friend URL in landing page
Close because landing page is in the scope of Cofacts Next project
meet.jit.si
Join a WebRTC video conference powered by the Jitsi Videobridge
今天想討論一下這樣的landing page走向o不ok? ok的話我就繼續把後面內容做完 (這版的寬是1024)
Figma
Created with Figma
g0v.hackmd.io
Comment on #249 Feature/new article details page ui
Nested `form` is introduced here, it's not valid DOM structure. Please remove one of the nesting form. <https://user-images.githubusercontent.com/108608/82548180-80b10400-9b8d-11ea-8586-e688044708a9.png|image>
Comment on #249 Feature/new article details page ui
If what we want is a horizontal scroll when there is not enough space, please use `overflowX: auto`. `overflow: scroll`: • introduces always-on scrolls, it's there even if no scroll is needed • scrolls both directions, which is pretty rare in design <https://user-images.githubusercontent.com/108608/82548608-28c6cd00-9b8e-11ea-8d28-c12bcd4ee7a6.png|image> I suggest web developers on Mac should turn on "always show scroll bars" at all times so that we can empathize Windows users more. It may be not obvious for Mac users with hidden scrollbars, the <https://www.filamentgroup.com/lab/scrollbars/|Windows users will always get ugly scroll bars for every `overflow: scroll` we write.>
Comment on #249 Feature/new article details page ui
Why overflow scroll here? It's introducing always-on horizontal & vertical scrolls. What can we get from `overflow: scroll`? <https://user-images.githubusercontent.com/108608/82547760-d33df080-9b8c-11ea-8849-65ffd3a13367.png|image>
Comment on #249 Feature/new article details page ui
seems that we are missing `flex: 1` here <https://user-images.githubusercontent.com/108608/82549705-ebfbd580-9b8f-11ea-8a54-c14b53537f7f.png|image>
Comment on #249 Feature/new article details page ui
`.aside`'s padding and `.similarMessageContainer`'s horizonal padding are stacked together on desktop. <https://user-images.githubusercontent.com/108608/82549939-53198a00-9b90-11ea-9a94-57d867a9bb50.png|image> Mockup: <https://user-images.githubusercontent.com/108608/82549998-72b0b280-9b90-11ea-8fb8-ec3f216da72b.png|image>
HackMD
g0v Hackath39n - 第參拾玖次又在家黑客松 - HackMD
g0v 線上百人黑客松用線上揪松(jothon online) + g0v 協作工具,讓您在家也能參加黑客松!
Figma
Created with Figma
Comment on #249 Feature/new article details page ui
<https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=1307%3A285|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=1307%3A285> the mobile version is horizontal scrolls
Comment on #249 Feature/new article details page ui
I'll change it to `overflow: auto` though, to hide scrollbar when user using windows
Comment on #136 Send new article & reply URLs to Wayback machine
Also, here is a tool that can send to multiple archivers: <https://github.com/oduwsdl/archivenow|https://github.com/oduwsdl/archivenow> There is a server mode available, thus it seems that we can directly dockerize the server so that rumors-api can invoke it whenever it got a url to archive.
HackMD
Youtube scrapping alternatives - HackMD
Youtube scrapping alternatives ===== :::info 相關討論 - [20200511 Slack](<https://g0v-tw.slack.com/arc>
jitsi.jothon.online
Join a WebRTC video conference powered by the Jitsi Videobridge
HackMD
Cofacts Hackath39n 協作頁面 - HackMD
Cofacts Hackath39n 協作頁面 ===== :::info - g0v slack channel:`#cofacts` - :handshake: 實體地點:[Workis 工作是](https
#191 Error: user doesn't grant required permissions yet
View details in Rollbar: <https://rollbar.com/mrorz/rumors-line-bot/items/216/|https://rollbar.com/mrorz/rumors-line-bot/items/216/> ``` Error: user doesn't grant required permissions yet File "<https://static.line-scdn.net/liff/edge/2.1/sdk.js>", line 2, in t File "<https://static.line-scdn.net/liff/edge/2.1/sdk.js>", line 2, in z File "<https://static.line-scdn.net/liff/edge/2.1/sdk.js>", line 2, in [anonymous] File "<https://static.line-scdn.net/liff/edge/2.1/sdk.js>", line 2, in [anonymous] File "<https://static.line-scdn.net/liff/edge/2.1/sdk.js>", line 2, in s File "[native code]", line unknown, in promiseReactionJob ```
Comment on #191 Error: user doesn't grant required permissions yet
I suspect this is because the user removed "send message to chatroom" function. Need help reproducing this bug. If this is confirmed, we should come up with a way to aid user enable the permission.
Comment on #249 Feature/new article details page ui
card added here <https://github.com/orgs/cofacts/projects/5#card-38799010|https://github.com/orgs/cofacts/projects/5#card-38799010>
Comment on #249 Feature/new article details page ui
card added here <https://github.com/orgs/cofacts/projects/5#card-38799032|https://github.com/orgs/cofacts/projects/5#card-38799032>
Comment on #249 Feature/new article details page ui
I think it's because that the logic here is to display feebacks with user present: ``` {feedbacks .filter(({ vote, user }) => vote === 'UPVOTE' && user) .map(feedback => ( <Feedback key={feedback.id} {...feedback} /> ))} ```
#168 [Refactor] remove duplicated input object types
Previously, every arithmetic input (with `{LT, GT, ...}`) has its own type, but they are almost the same -- there are only 2 types of such input throughout `rumors-api`, one is for integers, another for date strings. This PR replaces these `getArithmeticExpressionType` calls with 2 input object type instance to simplify the schema. Behavior of rumors-api should not be affected at all.
Figma
Created with Figma
g0v.hackmd.io
Comment on #249 Feature/new article details page ui
Got it, make sense. I am going to <https://g0v.hackmd.io/ZcoUOX_-RQSkJyl5xz4_Zg|revamp user handling>, giving users from `localhost` a dedicated browser app ID on staging site, and show browser app users to all apps. Hopefully this will solve these weird issue during development.
g0v.hackmd.io
src/graphql/queries/ListReplies.js:84
``` fields: ['text', 'reference'], ```
#51 Show related paragraphs in search result, instead of the first paragraphs
*Scenario* 1. LINE users seems not happy with the current "similarity" and tends to create new articles all the time. By showing the exact match of sentences may help them choose the identical articles. 2. Snippets / highlights can help Editors find interesting articles in the "related replies / articles" section. *Proposed solutions* API server should return matched paragraphs in each search result. LINE bot & website should display the search result in a manner similar to the <https://support.google.com/webmasters/answer/35624?hl=en|snippets in Google Search>. This is achievable via elastic search "highlighting" function. <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html|https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html>
g0v.hackmd.io
Review on #249 Feature/new article details page ui
Thanks for the update! I found some points not considered previously and has added as comments.
Comment on #249 Feature/new article details page ui
According to mockup, in the first line, we now always show `articleReply`'s author all the time. <https://user-images.githubusercontent.com/108608/82780423-b0ac2000-9e89-11ea-9b94-7f1354574c08.png|image> When `articleReply`'s author differs from the `reply` author, we show "originally written by XXX | original reply referenced N times" as extra info.
Comment on #249 Feature/new article details page ui
Although in the mockup, “Follow” function is actually excluded from current plan. Please remove the button for now.
Comment on #249 Feature/new article details page ui
Actually this button opens a form that submits reply request, thus `requestedForReply` flag should somehow affect this button. Currently mockup and spec did not consider the state of this button when the user has submitted a reply request (i.e. `requestedForReply` is `true`). I suggest changing the wording of the button to `Update comment` when `requestedForReply === true`. What do you think? <https://github.com/yanglin5689446|@yanglin5689446> <https://github.com/LucienLee|@LucienLee>
Comment on #249 Feature/new article details page ui
The time display here should not be `reply`'s `createdAt`. It should be the corresponding `articleReply`'s `createdAt` instead. <https://user-images.githubusercontent.com/108608/82780291-47c4a800-9e89-11ea-8227-9a791474f328.png|螢幕快照 2020-05-25 下午1 08 44> When A is using B's old reply, A is `articleReply.user` and B is `articleReply.reply.user`. B previously created the reply for another article; it's A that connects the reply to this article, thus we use A instead of B.
Comment on #249 Feature/new article details page ui
Consider using <https://material-ui.com/customization/default-theme/?expand-path=$.zIndex|`theme.zIndex.appBar`>, which takes modals, tooltips, snackbars into consideration as well.
Comment on #249 Feature/new article details page ui
Let's add `target="_blank"` here since the button says "in new tab"
Comment on #249 Feature/new article details page ui
[Trivial] Since all its child have `flex-grow`, we don't need `justifyContent` here
Review on #249 Feature/new article details page ui
The new search UI looks really nice! The use of context is good is also inspiring. Thank you for the implementation. Please find my trivial suggestions below.
Comment on #249 Feature/new article details page ui
The desktop now looks good in line clamp :) However, given the limited lines to display in this section, I think we don't need to add `nl2br`, so that we can reveal more text to the user. <https://user-images.githubusercontent.com/108608/82786769-c294bf80-9e97-11ea-8ad1-f492d20bb394.png|image>
Comment on #249 Feature/new article details page ui
> The desktop now looks good in line clamp :) > > However, given the limited lines to display in this section, I think we don't need to add `nl2br`, so that we can reveal more text to the user. > > <https://user-images.githubusercontent.com/108608/82786769-c294bf80-9e97-11ea-8ad1-f492d20bb394.png|image>
Comment on #249 Feature/new article details page ui
Clicking each similar-article item should go to article page. Forgot to add `<Link>` :P
Comment on #168 [Refactor] remove duplicated input object types
Unit test on travis is totally broken......
Comment on #168 [Refactor] remove duplicated input object types
Previously, `client.deleteByQuery` may delete nothing when `urls` index is not refreshed. This causes unit tests to fail if `CreateReply` unit test is executed before other unit tests that reads `urls` index. This manual refresh should make sure unit tests gets consistent results.
Review on #249 Feature/new article details page ui
We have come a long way to bring the article detail page to the current level. Good work! I believe we can deliver an upgrade to the current production site for a function complete editing experience very soon -- we are just few fixes away :muscle:
Comment on #249 Feature/new article details page ui
Next.js <https://nextjs.org/docs/api-reference/next/link|suggests> using `<a>` tag for `<Link>`'s children. I think we can directly change `.similarMessageContainer` to use `a` tag instead of `div`. Currently it do navigates user if they click the link, but if `<Link>` is combined with `<a>`, it allows user to cmd-click to open the link in new tab. We won't need `cursor: pointer` on the element as well, since `<a>` already turns cursor into pointer. (But we may need `text-decoration: none` to cancel out `<a>`'s default style, though.)
Comment on #249 Feature/new article details page ui
On desktop browser with a narrow screen, we get an inactive button: <https://user-images.githubusercontent.com/108608/82830907-9013b280-9ee9-11ea-89ac-1b8fb1744319.gif|share-no-use> Root cause is as described <https://github.com/cofacts/rumors-site/pull/249#discussion_r425051205|above> -- we only need one button that invokes `navigator.share` if it's available and shows dropdown otherwise.
#168 [Refactor] remove duplicated input object types
Previously, every arithmetic input (with `{LT, GT, ...}`) has its own input object type, but they are almost the same -- there are only 2 types of such input throughout `rumors-api`, one is for integers, another for date strings. This PR replaces these `getArithmeticExpressionType` calls with 2 input object type instance to simplify the schema. Behavior of rumors-api should not be affected at all.
Comment on #211 Entering article page from article list takes 2 back to go back to list page
I've observed that we won't get the issue if you comment out the `<Trendline />` component which is aligned with <https://github.com/cofacts/rumors-site/issues/211#issuecomment-586492770|iframe issue> that <https://github.com/normanlinnet|@normanlinnet> mentioned. I'll continue to dig into the problem and see if I can find a way to solve it.
Comment on #211 Entering article page from article list takes 2 back to go back to list page
Thank you <https://github.com/jihchi|@jihchi> for locating the component that caused this issue! We recently have <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=681%3A0|plans> to replace the iframe with line charts (data from Google Analytics reporting API). Let's hope the problem can go away soon. Removing "good first issue" because the root cause is identified as something we are going to deprecate soon.
#169 New API that lists article reply feedback
This PR implements `ListArticleReplyFeedback` API. *Use case* • As Cofacts team, I want to <https://cofacts.github.io/community-builder/#/bignum?start=2020-05-24T15%3A57&panels=useful|show number of new feedbacks generated> on website on the projector screen during editor meetups, so that I can encourage the participants. • As Cofacts team, I want to see new feedbacks generated this week and use them as insights when posting updates to editor's Facebook group, so that I can encourage editors in the community • As Cofacts editor, I want to see a list of new feedbacks on my article reply feedbacks in <https://g0v.hackmd.io/@NFi0czulSemxCM8RNSlz8Q/HJ8xT3QVU/%2FbbreV0ZqRDarHl4Zt5UpEw|my profile page>, so that I can acknowledge my contribution and understand what I can improve on. *Capability* • List article reply feedback in the database that can: • filter by`userId`, `appId`, `articleId`, `replyId` • filter by a range of `createdAt` or `updatedAt` • filter by feedback vote `1` or `-1` • filter by `comments` matching some keyword • sort by feedback vote, `createdAt` or `updatedAt` • Add necessary fields on `ArticleReplyFeedback` object type
Comment on #169 New API that lists article reply feedback
<https://coveralls.io/builds/31055976|Coverage Status> Coverage increased (+0.5%) to 86.506% when pulling *<https://github.com/cofacts/rumors-api/commit/a2881651da8fc1df653aec4aac47a3d0ec9f4ba1|a288165> on list-article-reply-feedback* into *<https://github.com/cofacts/rumors-api/commit/e7daf069d889f04cd2f20961eb2f2a5f2e8f7e48|e7daf06> on master*.
Comment on #249 Feature/new article details page ui
Trivial: `replyAuthor` seems not needed here
Review on #249 Feature/new article details page ui
LGTM! Let's ship it <https://github.githubassets.com/images/icons/emoji/shipit.png|:shipit:>
Comment on #249 Feature/new article details page ui
This flash message is never shown because `onClose()` unmounts `Snackbar`. Suggest moving snackbar to in `article/[id].js`.
Review on #249 Feature/new article details page ui
1 blocking issue discovered: `AppHeader` is covering `NewReplySection` on mobile. Seems that we should either use <https://material-ui.com/components/dialogs/#full-screen-dialogs|Material-ui Full screen dialog>, or at least applying <https://material-ui.com/customization/z-index/|`theme.zIndex.modal`>. <https://user-images.githubusercontent.com/108608/83000384-ddecff80-a03c-11ea-9ec7-6f3f343c4b34.png|image>
Comment on commit "Fix code review"
I think it's rare to see parent components passing a state setter function down to its children. • I suggest making `NewReplySection`'s only responsibility would be invoking event handlers like `onSubmissionComplete`. `article/[id].js` should invoke `setFlashMessage` when handling `onSubmissionComplete` . • It's OK for `createReply` and `connectReply` to show the same flash message "The reply has been submitted.". We can add `onError` prop as error handler to `NewReplySection`, invoking the callback on error. However, I think it's also OK if we directly invoke `alert()` on error, or process errors within `NewReplySection`.
#192 TypeError: Cannot read property 'sessionId' of undefined
View details in Rollbar: <https://rollbar.com/mrorz/rumors-line-bot/items/220/|https://rollbar.com/mrorz/rumors-line-bot/items/220/> ``` TypeError: Cannot read property 'sessionId' of undefined File "/app/build/webhook/index.js", line 89, in singleUserHandler if (data.sessionId !== context.data.sessionId) { File "<anonymous>", line unknown, in runMicrotasks File "internal/process/task_queues.js", line 97, in processTicksAndRejections ```
Comment on #192 TypeError: Cannot read property 'sessionId' of undefined
Should figure out how to reproduce. Which one is undefined, `data` or `context.data`?
#255 Upgrade babel-preset-env to fix storybook build issue.
Ref: <https://github.com/storybookjs/storybook/issues/10477#issuecomment-635075061|storybookjs/storybook#10477 (comment)> Reproduce: 1. `docker pull node:12` 2. `IMAGE_NAME=rumors-site-test hooks/build` 3. See build error like this one: <https://user-images.githubusercontent.com/108608/83101336-b2bdeb00-a0e4-11ea-84e5-bfb14cdc796e.png|image> This PR follows suggestions in <https://github.com/storybookjs/storybook/issues/10477|storybookjs/storybook#10477> to fix the build error.
Update search page, make replies search works. mockup: <https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=432%3A2727|https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=432%3A2727>
Stack Overflow
Why don't flex items shrink past content size?
I have 4 flexbox columns and everything works fine, but when I add some text to a column and set it to a big font size, it is making the column wider than it should be due to the flex property. I ...
#170 Add "types" filter for ListReplies
<https://www.figma.com/file/zpD45j8nqDB2XfA6m2QskO/Cofacts-website?node-id=299%3A403|Reply page mockup> requires a multi-select reply type filter for `ListReplies`. This PR: • implements `ListReplies`'s `types` filter. • add snapshot name to test cases that has multiple snapshot files so that it's easier to do code review.
Comment on #170 Add "types" filter for ListReplies
<https://coveralls.io/builds/31110287|Coverage Status> Coverage increased (+0.07%) to 86.578% when pulling *<https://github.com/cofacts/rumors-api/commit/970a0b46c2308c41197337f10a5412e6c8e5dbd1|970a0b4> on listreply-multiple-type* into *<https://github.com/cofacts/rumors-api/commit/a2b89f7014dfa4c901ffab6d10c78b833278f297|a2b89f7> on master*.
#171 Multiple ArticleReplyFeedback filters should narrow down selection
Currently if we specify multiple filters to `ArticleReplyFeedback`, the search result will be the union of all filters: • Filter: `{createdAt: {GT: "2020-05-29T00:00:00Z"}}` • Result `totalCount`: 26 • Filter: `{createdAt: {GT: "2020-05-29T00:00:00Z"}, vote: UPVOTE}` • Result`totalCount`: 145358 This PR changes the behavior to intersection so that the filter is more useful. *Root cause* Originally the filters are attached to `shouldQueries`. However, we allow elasticsearch to include items that matches only 1 should cause. `shouldQueries` should be only used in queries that involves relevance scoring, such as `more_like_this`.
Comment on #171 Multiple ArticleReplyFeedback filters should narrow down selection
<https://coveralls.io/builds/31111158|Coverage Status> Coverage remained the same at 86.578% when pulling *<https://github.com/cofacts/rumors-api/commit/2d1471faf2a5bd61a0f25badc424c2b352ba45d7|2d1471f> on fix-arf-multi-filter* into *<https://github.com/cofacts/rumors-api/commit/1ef3790da93aec2ee26426d5561766ff1708ae13|1ef3790> on master*.
#172 Implement articleRepliesFrom filter for ListArticles
Fixes <https://github.com/cofacts/rumors-api/issues/165|#165> • Implements `articleRepliesFrom` in <https://github.com/cofacts/rumors-api/issues/165|#165> • Drops `appId` because `userId` should be sufficient according to <https://g0v.hackmd.io/ZcoUOX_-RQSkJyl5xz4_Zg#%E6%96%B9%E5%90%91-2-%E9%87%9D%E5%B0%8D%E6%AF%8F%E5%80%8B-backend-user-%E9%83%BD%E7%94%A2%E7%94%9F%E4%B8%80%E5%80%8B-user-document|`userId` / `appId` management proposal> • I cannot think of any useful use case filtering article-reply's `appId` yet • Fixes `categoryIds` and `hasArticleReplyWithMorePositiveFeedback`, which unions its results when used with other filters and is incorrect • Similar to <https://github.com/cofacts/rumors-api/pull/171|#171>, please see <https://github.com/cofacts/rumors-api/pull/171|#171> for explanation.
Comment on #172 Implement articleRepliesFrom filter for ListArticles
<https://coveralls.io/builds/31113234|Coverage Status> Coverage increased (+0.4%) to 86.933% when pulling *<https://github.com/cofacts/rumors-api/commit/315b7a48dec52eb6ce99ad214622d713e0d25bd3|315b7a4> on user-filter* into *<https://github.com/cofacts/rumors-api/commit/1ef3790da93aec2ee26426d5561766ff1708ae13|1ef3790> on master*.
#257 [Hotfix] Fix reply form empty submission bug
Ref: <https://www.facebook.com/groups/cofacts/permalink/2702689166629562/|https://www.facebook.com/groups/cofacts/permalink/2702689166629562/> *Impact* All reply submission. No one can submit new replies to Cofacts now. *Root cause* In `NewReplySection/index`, `handleSubmit` is picking up old `fields` variable, which is always empty. *Proposed fix* • Add `fields` to `useCallback` deps • TODO: Make eslint emit error on omitted dependency
material-ui.com
Circular, Linear progress React components - Material-UI
Progress indicators commonly known as spinners, express an unspecified wait time or display the length of a process. The animation works with CSS, not JavaScript.
#258 Enable react hook lint rules
This PR enables react-hooks eslint rules and fixes all errors. All violation of `react-hooks/exhausive-deps` now triggers build failure and requires explicitly disabling it using line comments (also need to include a good reason in comment!). Current violations are fixed using the following rules: • `useCallback`: 1. curried callbacks (`item => () => {}`) should not put in `useCallback` because when it's used in event handlers, curry function is invoked and a new copy of handler is always returned. There is no use putting `useCallback` over curried callbacks. 2. event handlers depending on other function that is not memoized: its dependency will change every render. I remove its `useCallback` in this case. 3. otherwise, add dependency to array. • `useEffect`: 1. If it's meant to be a `componentDidMount`, I disable the rule for that line. 2. If it's meant to be invoked on dependency change, I add the remaining dependencies. *Each code change in this PR may introduce hard-to-find bugs. Please inspect carefully.*